﻿using System;
using System.Reflection;
using LuceneApiServerLib.Core;
using LuceneApiServerLib.Util;

namespace LuceneApiServerLib
{
    /// <summary>
    ///     表示属性
    /// </summary>
    public class LnProperty
    {
        /// <summary>
        ///     属性的Get委托
        /// </summary>
        private readonly ApiAction geter;

        /// <summary>
        ///     属性的Set委托
        /// </summary>
        private readonly ApiAction seter;

        /// <summary>
        ///     Get属性
        /// </summary>
        /// <param name="property">属性</param>
        public LnProperty(PropertyInfo property)
        {
            Name = property.Name;
            PropertyType = property.PropertyType;
            var attr = Attribute.GetCustomAttribute(property, typeof (FieldAttribute)) as FieldAttribute;
        
            if (attr != null) 
            {
                Index = attr.Index;
                Store = attr.Store;
            }
            SortType = GetLnSortType(property.PropertyType);

            geter = new ApiAction(property.GetGetMethod());
            seter = new ApiAction(property.GetSetMethod());
        }

        /// <summary>
        ///     获取属性名
        /// </summary>
        public string Name { get; private set; }

        /// <summary>
        ///     设置分词索引
        /// </summary>
        public Index Index { get; set; }

        /// <summary>
        ///     设置存储
        /// </summary>
        public Store Store { get; set; }

        /// <summary>
        ///     获取属性的类型
        /// </summary>
        public Type PropertyType { get; private set; }

        /// <summary>
        ///     获取属性的排序类型
        /// </summary>
        public LnSortType SortType { get; private set; }

        /// <summary>
        ///     获取属性的值并转换为字符串
        /// </summary>
        /// <param name="instance">实例</param>
        /// <returns></returns>
        public string GetValue(object instance)
        {
            var value = geter.Execute(instance);
            if (value == null)
            {
                return "";
            }

            // 枚举转换为整型的字符串
            if (PropertyType.IsEnum)
            {
                return value.GetHashCode().ToString();
            }
            return value.ToString();
        }

        /// <summary>
        ///     设置属性的值
        /// </summary>
        /// <param name="instance">实例</param>
        /// <param name="value">属性值</param>
        public void SetValue(object instance, string value)
        {
            var castValue = Converter.Cast(value, PropertyType);
            seter.Execute(instance, castValue);
        }

        /// <summary>
        ///     排序字段类型转换
        /// </summary>
        /// <param name="type">字段类型</param>
        /// <returns></returns>
        private static LnSortType GetLnSortType(Type type)
        {
            if (type == typeof (string) || type == typeof (Guid) || type == typeof (DateTime))
            {
                return LnSortType.STRING;
            }
            if (type == typeof (double))
            {
                return LnSortType.DOUBLE;
            }
            if (type == typeof (float) || type == typeof (decimal))
            {
                return LnSortType.FLOAT;
            }
            if (type == typeof (short) || type == typeof (ushort))
            {
                return LnSortType.SHORT;
            }
            if (type == typeof (int) || type == typeof (uint) || type.IsEnum)
            {
                return LnSortType.INT;
            }
            if (type == typeof (long) || type == typeof (ulong))
            {
                return LnSortType.LONG;
            }
            if (type == typeof (byte))
            {
                return LnSortType.BYTE;
            }
            return LnSortType.SCORE;
        }

        /// <summary>
        ///     字符串显示
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return Name;
        }
    }
}